import { app, BrowserWindow, ipcMain, IpcRenderer } from 'electron';
import { join, resolve } from 'path';
import { parse } from 'url';
import { IEvents } from '../interfaces';
import config from '../utils/config';
import is_app_event from './is-app-event';

const FD_EVENTS_INIT = 'fd-events-init';

function create_main_window() {
	const { main, maximizable } = config.APP;
	const url = (() => {
		const p = parse(main);
		if (!p.protocol) {
			return join('file://', resolve(main));
		} else {
			return main;
		}
	})();
	const win = new BrowserWindow({
		maximizable,
		titleBarStyle: 'hiddenInset',
		webPreferences: {
			nodeIntegrationInWorker: true
		}
	});

	// and load the index.html of the app.
	win.loadURL(url);

	// Open the DevTools.
	if (config.debug) {
		win.webContents.openDevTools();
		const watch = require('watch') as {
			watchTree(dir: string, cb: () => void): void;
		};
		watch.watchTree('./dist/', () => {
			win.reload();
		});
	}

	// Emitted when the window is closed.
	win.on('closed', () => {
		// Dereference the window object, usually you would store windows
		// in an array if your app supports multi windows, this is the time
		// when you should delete the corresponding element.
		(global as any).main_win = null;
	});
	if (maximizable) {
		win.maximize();
	}
	(global as any).main_win = win;
	return win;
}

interface IDesktopMsg {
	reply: string;
	action: string;
	spaceid: string;
	msg: unknown;
}

export default function init_events(events: IEvents, emit: (event: string, ...args: any[]) => Promise<any> | undefined) {
	for (const event in events) {
		if (event === FD_EVENTS_INIT) {
			continue;
		}
		if (is_app_event(event)) {
			app.on(event as any, (e) => {
				return emit(event, e);
			});
		} else {
			throw new Error(`not supported event [${event}]`);
		}
	}

	if (process.platform === 'linux') {
		// todo: fix: black window under linux(Electron 3).
		app.disableHardwareAcceleration();
	}
	app.on('window-all-closed', () => {
		// On macOS it is common for applications and their menu bar
		// to stay active until the user quits explicitly with Cmd + Q
		if (process.platform !== 'darwin') {
			app.quit();
		}
	});
	app.once('ready', create_main_window);
	ipcMain.on('msg-pipe', async ({ sender }: { sender: IpcRenderer; }, { action, msg, reply }: IDesktopMsg) => {
		try {
			const data = await emit(action, msg);
			sender.send(reply, {
				data
			});
		} catch (ee) {
			const err = ee as Error;
			sender.send(reply, {
				errMsg: err.message
			});
		}
	});
}
